/*
 * Copyright (C) 2008 Florian Gilles
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

var selectionlinks = {

    prefs: null,
    
    onLoad: function() {
        this.initialized = true;
        
        this.prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.selectionlinks.");
        
        // set preferences (see defaults.js)
        if (!this.prefs.prefHasUserValue("fetchanchor")) this.prefs.setBoolPref("fetchanchor", true);
        if (!this.prefs.prefHasUserValue("fetchtext"))   this.prefs.setBoolPref("fetchtext", true);
        if (!this.prefs.prefHasUserValue("duplicates"))  this.prefs.setBoolPref("duplicates", false);
        if (!this.prefs.prefHasUserValue("debug"))       this.prefs.setBoolPref("debug", false);
        if (!this.prefs.prefHasUserValue("openas"))      this.prefs.setIntPref("openas", 2);
          
        // Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).savePrefFile(null);
        
        // add event listener
        document.getElementById("contentAreaContextMenu").addEventListener("popupshowing", selectionlinks.onPopupShowing, false);
    },
        
    onPopupShowing: function() {
        gContextMenu.showItem("context-selectionlinks-open",      gContextMenu.isTextSelected);
        gContextMenu.showItem("context-selectionlinks-download",  gContextMenu.isTextSelected);
        gContextMenu.showItem("context-selectionlinks-seperator", gContextMenu.isTextSelected);       
    },
        
    arrayContains: function(ar, q)
    {
        var result = false;
        
        for (var i = 0; i < ar.length; i++) 
        {  
            if (ar[i] === q)
            {
                result = true;
                break;
            }   
        }
        
        return result;
    },
    
    validUri: function(q)
    {   
        var reg = new RegExp();
        reg.compile("([a-zA-Z0-9][a-zA-Z0-9._-]*\\.)*[a-zA-Z0-9][a-zA-Z0-9._-]*\\.[a-zA-Z]{2,5}");
        return reg.test(q.toLowerCase());       
    },
   
	trimStr: function(s)
	{
		s = s.replace(/^\s+/, "");  // remove leading spaces
		s = s.replace(/\s+$/, "");  // remove trailing spaces
		s = s.replace(/\s+/g, " "); // collapse multiple spaces
		return s;
	},
	
    removeTags: function(s)
    {
        // http://www.w3.org/TR/REC-html40/index/elements.html
        s = s.replace(/&(lt|gt);/g, function (strMatch, p1) { return (p1 == "lt")? "<" : ">"; });
        
        // don't collapse text seperated by the following tags
        s = s.replace(/<\/?[br][^>]+(>|$)/g,   " ");
        s = s.replace(/<\/?[div][^>]+(>|$)/g,  " ");   
        s = s.replace(/<\/?[span][^>]+(>|$)/g, " ");   
        s = s.replace(/<\/?[h1][^>]+(>|$)/g,   " ");     
        s = s.replace(/<\/?[hr][^>]+(>|$)/g,   " ");     
        s = s.replace(/<\/?[p][^>]+(>|$)/g,    " ");     
        s = s.replace(/<\/?[li][^>]+(>|$)/g,   " ");     
        
        // finally collapse remaining text 
        s = s.replace(/<\/?[^>]+(>|$)/g,      ""); // e.g. www.example.<b>com</b>
        return s;
    }, 
	  
    fetchAnchorLinks: function(links, node) 
    {       
        if (node.nodeType == 1 && node.tagName == "A")
        {
            var q = this.trimStr(node.href); // trim string

            if (this.validUri(q))
            {  
                if (this.arrayContains(links, q))
                {
                    if (prefs.getBoolPref("duplicates"))
                    {
                        links.push(q);                                        
                    }
                }
                else
                {
                    links.push(q);                
                }
            }      
            
            // remove anchor
            node.parentNode.removeChild(node);       
        }
        
        // parse children 
        if (node.hasChildNodes() && node.tagName != "A") 
        { 
            for (var i = 0; i < node.childNodes.length; i++) 
            { 
                this.fetchAnchorLinks(links, node.childNodes[i]);
            } 
        }
    },    
        
    fetchTextLinks: function(links, text) 
    {       
        //text = text.toLowerCase();    // lower case
        text = this.removeTags(text); // remove tags
        text = this.trimStr(text);    // trim string
        
        if (text.length > 0)
        {
            var p = text.split(" ");

            for (i = 0; i < p.length; i++)
            {
                if (this.validUri(p[i]))
                {  
                    if (this.arrayContains(links, p[i]))
                    {
                        if (prefs.getBoolPref("duplicates"))
                        {
                            links.push(p[i]);                                        
                        }
                    }
                    else
                    {
                        links.push(p[i]);                
                    }
                }            
            }
        }
    },

    parseSelection: function(type) {
                           
        // array containing links to open
        var links = new Array();
        
        var focusedWindow = document.commandDispatcher.focusedWindow;
                 
        if (!focusedWindow || focusedWindow == window)
        {
            focusedWindow = content;
        }
        
        if (focusedWindow.getSelection()) 
        {
            // create dummy node
            var node = focusedWindow.document.createElement("div");
            node.appendChild(focusedWindow.getSelection().getRangeAt(0).cloneContents());
 
            // fetch anchor links 
            if (prefs.getBoolPref("fetchanchor"))
            {
                this.fetchAnchorLinks(links, node);
            }
                        
            // fetch text links      
            if (prefs.getBoolPref("fetchtext"))
            {
                this.fetchTextLinks(links, new XMLSerializer().serializeToString(node)); // node.innerHTML                
            }   
        }
        else
        {
            // nothing selected
        }  
        
        // process action
        if (!prefs.getBoolPref("debug"))
        {
            switch (type)
            {
                // open selected links
                case 0:
                    for (var i = 0; i < links.length; i++)
                    {
                        // http://developer.mozilla.org/en/Code_snippets/Tabbed_browser
                        switch (prefs.getIntPref("openas"))
                        {
                            case 0: // new windows
                                openDialog("chrome://browser/content/browser.xul", "_blank", "chrome,all,dialog=no", links[i]);
                                break;
                            
                            case 1: // new tabs
                                gBrowser.addTab(links[i]);
                                break;
                            
                            case 2: // new active tabs
                                gBrowser.selectedTab = gBrowser.addTab(links[i]);
                                break;
                            
                            default: // new active tabs
                                gBrowser.selectedTab = gBrowser.addTab(links[i]);
                                break;
                        }                    
                    }
                    break;

                // download selected links
                case 1:
                    for (var i = 0; i < links.length; i++)
                    {               
                        //saveURL(aURL, aFileName, aFilePickerTitleKey, aShouldBypassCache, aSkipPrompt, aReferrer)
                        saveURL(links[i], null, null, false, true, null);
                    }  
                    break;
            }
        }
                 
        // debug output
        if (prefs.getBoolPref("debug"))
        {           
            var s, d = new Array("open","download");
            s += "type="+type+"-"+d[type]+"";
            s += ";fetchanchor="+(prefs.getBoolPref("fetchanchor") ? "true" : "false");
            s += ";fetchtext="+(prefs.getBoolPref("fetchtext") ? "true" : "false"); 
            s += ";duplicates="+(prefs.getBoolPref("duplicates") ? "true" : "false"); 
            s += ";debug="+(prefs.getBoolPref("debug") ? "true" : "false");
            s += ";openas="+prefs.getIntPref("openas");
            s += "\n\n";
            s += links.length+" links found\n\n"; 

            for (i = 0; i < links.length; i++)
            {
                if (links[i].length > 0)
                {
                    s += "["+i+"] "+links[i]+"\n";
                }   
            }
            
            alert(s);
        }
    },
};

window.addEventListener("load", selectionlinks.onLoad, false);

